﻿namespace Jhong.FunMVC
{
    using System;
    using System.Linq;
    using System.Reflection;

    public abstract partial class Controller
    {
        private ActionInvoker _actionInvoker;

        public Controller()
        {
            this._actionInvoker = new ActionInvoker();
        }

        public Request Request { get; set; }

        public Response Response { get; set; }

        internal void Execute(ControllerContext context)
        {
            Response.Headers["PowerBy"] = "FunMVC";
            Response.Headers["MyMaster"] = "小蝶惊鸿";
            if (false == OnAuthorization()) return;
            if (this._endInvokeAction) return;
            try
            {
                var outputCache = ResponseCache.GetCache(Request.Uri.AbsoluteUri);
                if (null != outputCache)
                {
                    outputCache.ChangeOwinResponse(context.Response);
                    context.Response = outputCache;
                }
                else
                {
                    this._actionInvoker.InvokeAction(context);
                }
            }
            catch (Exception ex)
            {
                ThrowExceptionHandler.ThrowException(context.Request, context.Response, ex);
                this.OnException(new ExceptionContext(this.Request, ex));
            }
        }

        protected virtual bool OnAuthorization()
        {
            return true;
        }

        public void Redirect(string url, bool permanent)
        {
            if (permanent) Response.HttpStatusCode = 301;
            else Response.HttpStatusCode = 302;
            Response.Headers.Add("Location", url);
        }

        public void Redirect(string url)
        {
            this.Redirect(url, false);
        }

        public ActionResult RedirectToAction(string actionName)
        {
            return this.RedirectToAction(actionName, this);
        }

        public ActionResult RedirectToAction(string actionName, object[] parameter)
        {
            return this.RedirectToAction(actionName, this, parameter);
        }

        public ActionResult RedirectToAction(string actionName, Controller controller)
        {
            return this.RedirectToAction(actionName, controller, new object[0]);
        }

        public ActionResult RedirectToAction(string actionName, Controller controller, object[] parameter)
        {
            this._endInvokeAction = true;
            if (false == controller.GetHashCode().Equals(this))
            {
                controller.Request = this.Request;
                controller.Response = this.Response;
                controller.Request.Controller = controller.GetType().Name.Replace("Controller", string.Empty);
                controller.Request.Action = actionName;
            }
            MethodInfo method = null;
            var methods = controller.GetType().GetMethods().Where(s => s.Name == actionName);
            if (methods.Count() == 1)
            {
                method = methods.First();
            }
            else
            {
                foreach (var m in methods)
                {
                    var attr = Attribute.GetCustomAttribute(m, typeof(HttpMethodAttribute));
                    if (null == attr)
                    {
                        if (null == method) method = m;
                        else throw new Exception(string.Format("存在多个符合命中规则的{0}", actionName));
                        continue;
                    }
                    if (null == (attr as HttpGetAttribute)) continue;
                    if (null == method) method = m;
                    else throw new Exception(string.Format("存在多个符合命中规则的{0}", actionName));
                }
            }
            var result = method.Invoke(controller, parameter) as ActionResult;
            if (null != result) result.Execute();
            return new NullResult();
        }

        private bool _endInvokeAction;

        public virtual void OnException(ExceptionContext context)
        {
        }

        public JsonResult Json(object data, bool allowHttpGet)
        {
            if (false == allowHttpGet)
            {
                if (this.Request.Method.IndexOf("GET") >= 0)
                {
                    return new JsonResult("禁止GET访问", this.Response);
                }
            }
            return new JsonResult(data, this.Response);
        }

        public JsonResult Json(object data)
        {
            return this.Json(data, false);
        }

        public ContentResult Content(string txt)
        {
            return new ContentResult(txt, this.Response);
        }

        public ViewResult View()
        {
            return this.View(this.Request.Action);
        }

        public ViewResult View(string viewName)
        {
            return this.View(viewName, null);
        }

        //public ViewResult View(object model)
        //{
        //    return this.View(this.Request.Action, model);
        //}

        private ViewResult View(string viewName, object model)
        {
            var instance = ViewResult.GetResultInstance(this.Response);
            instance.ViewName = viewName;
            instance.Model = model;
            instance.ControllerName = this.Request.Controller;
            instance.ViewData = this.ViewData;
            return instance;
        }

        public ViewDataDictionory ViewData = new ViewDataDictionory();

        private static readonly string _rootPath = GetRootPath();

        private static string GetRootPath()
        {
            var path = AppDomain.CurrentDomain.GetData(".appPath").ToString();
            if (string.IsNullOrWhiteSpace(path)) path = Environment.CurrentDirectory;
            return path;
        }

        public string WebSiteRootPath
        {
            get
            {
                return _rootPath;
            }
        }
    }
}